package fifo

import "fmt"

type FIFO struct {
	q        []interface{}
	m        map[string]int
	v        map[int]string
	capacity int
	head     int
	tail     int
}

func NewFIFO(n int) *FIFO {
	return &FIFO{
		q:        make([]interface{}, n),
		m:        make(map[string]int),
		v:        make(map[int]string),
		capacity: n,
		head:     0,
		tail:     0,
	}
}

func (this *FIFO) Set(key string, v interface{}) bool {
	_, ok := this.m[key]
	if ok {
		return false
	}
	if this.head == this.tail {
		this.q[this.head] = v
		this.m[key] = this.head
		this.v[this.head] = key
		this.tail++
		return true
	}
	if this.tail < this.capacity-1 {
		this.tail++
	}
	for i := this.tail; i > this.head; i-- {
		this.q[i] = this.q[i-1]
		this.m[this.v[i-1]]++
		this.v[this.m[this.v[i-1]]] = this.v[i-1]
		this.v[i-1] = ""
	}
	this.q[this.head] = v
	this.m[key] = this.head

	return true
}

func (this *FIFO) Get(key string) interface{} {
	index, ok := this.m[key]
	if !ok {
		return nil
	}
	if index == this.head {
		return this.q[this.head]
	}
	indexV := this.q[index]
	for i := this.head; i < index; i++ {
		this.q[i] = this.q[i-1]
	}
	this.q[this.head] = indexV
	return indexV
}

func (this *FIFO) EnQueue(v interface{}) bool {
	if this.tail == this.capacity {
		return false
	}
	this.q[this.tail] = v
	this.tail++
	return true
}

func (this *FIFO) DeQueue() interface{} {
	if this.head == this.tail {
		return nil
	}
	v := this.q[this.head]
	this.head++
	return v
}

func (this *FIFO) Print() string {
	if this.head == this.tail {
		return "empty queue"
	}
	result := "head"
	for i := this.head; i <= this.tail-1; i++ {
		result += fmt.Sprintf("<-%+v", this.q[i])
	}
	result += "<-tail"
	return result
}
